import hashlib
import re
import random
import uuid
import math
import string

from hashids import Hashids
import numpy as np


class Utils(object):
    @staticmethod
    def md5(data: str):
        '''
            字符串转 md5
        '''
        return hashlib.md5(data.encode(encoding='utf-8')).hexdigest()

    @staticmethod
    def clear_article(content):
        """基础清洗

        Args:
            content (string): 采集通稿内容

        Returns:
            string: 完成基础清洗
        """
        # 清洗 \r\n\t ( ) 半角空格 (　) 全角空格
        new_content = content.replace("\r", '').replace("\n", '').replace("\t", '').replace(" ", '').replace("　", '')
        # 清洗 &nbsp; 半角不断行的空白格 &emsp; 全角空格 &ensp; 半角空格
        new_content = new_content.replace("&nbsp;", '').replace("&emsp;", '').replace("&ensp;", '') \
            .replace('&mdash;', '').replace('&ldquo;', '').replace('&rdquo;', '')
        # 清洗 <br /> <br> html标签
        # HTML标签
        re_h = re.compile('</?\w+[^>]*>')
        new_content = re_h.sub('', new_content)
        # http 后面的内容全删
        new_content, part, end_part = new_content.partition('http')
        # 完成
        return new_content

    @staticmethod
    def create_serial_number(number: int, length=6) -> str:
        f = '{:0=' + str(length) + '}'
        return f.format(number)

    @staticmethod
    def create_big_random_number(length=10):
        code = []
        for i in range(length):
            code.append(random.choice(string.digits))
        return ''.join(code)

    @staticmethod
    def create_random_number(length=6):
        start_number = 10**(length - 1)
        end_number = 10**length - 1

        ret = random.sample(range(start_number, end_number), 1)

        return ret[0]

    @staticmethod
    def get_alphabet(type=1):
        # 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        if type == 1:
            # 数字
            return string.digits
        elif type == 2:
            # 大写字母
            return string.ascii_uppercase
        elif type == 3:
            # 小写字母
            return string.ascii_lowercase
        elif type == 4:
            # 大小写字母
            return string.ascii_uppercase + string.ascii_lowercase
        elif type == 5:
            # 大写字母数字
            return string.digits + string.ascii_uppercase
        elif type == 6:
            # 小写字母数字
            return string.digits + string.ascii_lowercase
        else:
            return ''

    @staticmethod
    def create_random_hash_str(number=1, length=8, salt='code', type=0):
        # 获取字符串
        alphabet = Utils.get_alphabet(type)
        hashids = Hashids(salt=salt, min_length=length, alphabet=alphabet)
        return hashids.encode(number)

    @staticmethod
    def create_random_int(length=9, dtype=np.uint64):
        low = (10**(length - 1))
        high = (10**length) - 1
        list_int = np.random.randint(low=low, high=high, size=1, dtype=dtype)
        return list_int[0]

    @staticmethod
    def create_random_integer(length=9, size=1, dtype=np.uint64):
        low = (10**(length - 1))
        high = (10**length) - 1
        return np.random.randint(low=low, high=high, size=size, dtype=dtype)

    @staticmethod
    def create_random_integer_new(length=9, seed=0, size=100, dtype=np.uint64):
        if seed > 0:
            np.random.seed(seed)

        low = (10**(length - 1))
        high = (10**length) - 1
        print(f'seed:{seed}, low:{low}, high:{high}')
        return np.random.randint(low=low, high=high, size=size, dtype=dtype)

    @staticmethod
    def create_random_str(length=6, base_str='abcdefghigklmnopqrstuvwxyz0123456789') -> str:
        base_length = len(base_str) - 1
        str_list = [base_str[random.randint(0, base_length)]
                    for i in range(length)]

        return ''.join(str_list)

    @staticmethod
    def create_hashids_str(number: int, salt='5ebe2294ecd0e0f08eab7690d2a6ee69', min_length: int = 6):
        """
        number 转换的字符
        salt 加密盐 默认 md5(secret)
        min_length 最小长度 6位
        """
        hashids = Hashids(salt=salt, min_length=min_length, alphabet='abcdefghigklmnopqrstuvwxyz0123456789')
        return hashids.encode(number)

    @staticmethod
    def int_to_hex(number: int) -> str:
        return hex(number)[2:]

    @staticmethod
    def hex_to_int(hex_str: str) -> int:
        return int(hex_str, 16)

    @staticmethod
    def create_md5(md5_str: str) -> str:
        md5 = hashlib.md5()
        md5.update(md5_str.encode('utf-8'))
        return md5.hexdigest()

    @staticmethod
    def letter_alphabet(num):
        '''生成序号前字母'''
        index_s = ''
        while (num > 0):
            m = num % 26
            if m == 0: m = 26
            index_s = chr(m + 64) + index_s
            num = math.floor((num - m) / 26)
        return index_s

    @staticmethod
    def batch_sn_encode(num, num_length=4):
        if num < 0:
            raise Exception('Number can\'t be less than 0')

        number = num % 10**num_length
        alpha_num = num // 10**num_length + 1

        alpha = Utils.letter_alphabet(alpha_num).lower()

        return alpha + str(number).zfill(num_length)

    @staticmethod
    def batch_sn_decode(batch_sn, num_length=4):
        alpha_pattern = re.compile('^([a-z]+)')
        num_pattern = re.compile('(\d+)$')

        alpha = alpha_pattern.findall(batch_sn)
        num = num_pattern.findall(batch_sn)

        if len(alpha) == 0 or len(num) == 0:
            raise Exception('Number can\'t be less than 0')

        alpha = alpha[0].upper()

        start_index = 1
        start_alpha = 'A'
        while (alpha != start_alpha):
            start_index += 1
            start_alpha = Utils.letter_alphabet(start_index)

        num = (10**num_length * (start_index - 1)) + int(num[0])

        return num

    @staticmethod
    def company_uuid(length=8):
        '''商户UUID'''
        return uuid.uuid4().hex[:length]

    @staticmethod
    def create_uuid(length=8):
        '''UUID'''
        return uuid.uuid4().hex[:length]

    @staticmethod
    def convertDex2Hex36(num):
        map = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')
        result = ''
        if int(num) < 10:
            result = str(num)
        else:
            dis = math.floor(int(num) / 36)
            res = int(num) % 36
            if dis > 0 and dis < 10:
                result += str(dis)
            elif dis >= 10:
                result += Utils.convertDex2Hex36(dis)
            if res >= 10:
                result += map[res - 10]
            else:
                result += str(res)
        return result

    @staticmethod
    def convertHex362Dex(num):
        map = (
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
            'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
            'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
        )
        result = 0
        len_char = len(num)
        for index, char_s in enumerate(num):
            try:
                if map.index(char_s):
                    result += map.index(char_s) * (36**(len_char - 1 - index))
            except Exception as e:
                result += int(char_s) * (36**(len_char - 1 - index))

        return result
